'==============================================================================================================
'MListTemplate 通用链表模板
'可以根据自己需要设置链表数据类型
'rainheart 1493446087 整理、修改，原版请到FB论坛找
'使用说明：
'在VFB工程“程序起始模块”中包含本文件(假设文件放在工程的modules文件夹内，其他路径根据路径修改)
'#include Once "../modules/list.bi"   '包含链表头文件
'MListTemplate(Long)                  '声明链表类型为long,也可以是自定义类型
'类型声明后，链表数据类型如下(以long为例)：
'链表节点类型为：TLISTNODELong  '即TLISTNODE + 数据类型
'链表类型为：    TLISTLong      '即TLIST + 数据类型
'2022-01-20 rainheart 1493446087
'修改GetValueIndex函数中的条件判断，去掉exit function,因为在自定义数据类型时会出现编译错误


#macro MListTemplate(list_type)   
    #Ifndef TLISTNODE##list_type
        Type TLISTNODE##list_type 
            xValue As list_type
            pPrev As TLISTNODE##list_type Ptr = 0
            pNext As TLISTNODE##list_type Ptr = 0
        End Type
    #endif
    #ifndef TLIST##list_type
        Type TLIST##list_type
            pFirst As TLISTNODE##list_type Ptr = 0
            pLast As TLISTNODE##list_type Ptr = 0
            iSize As Long = 0
            Declare Destructor()
            Declare Sub Add(xValue As list_type)
            Declare Sub InsertItemIndex(iIndex As Long , xValue As list_type)
            Declare Sub InsertItem(pItem As TLISTNODE##list_type Ptr, xValue As list_type)
            Declare Sub DeleteItemIndex(iIndex As Long)
            Declare Sub DeleteItem(pItem As TLISTNODE##list_type Ptr)
            Declare Sub DeleteAll()
            Declare Sub SetValueIndex(iIndex As Long , xValue As list_type)
            Declare Sub SetValue(pItem As TLISTNODE##list_type Ptr , xValue As list_type)
            Declare Sub MoveItemIndex(iIndexFrom As Long , iIndexTo As Long)
            Declare Sub MoveItem(pItemFrom As TLISTNODE##list_type Ptr , pItemTo As TLISTNODE##list_type Ptr)
            Declare Function GetFirst() As TLISTNODE##list_type Ptr
            Declare Function GetLast() As TLISTNODE##list_type Ptr
            Declare Function GetNext(pItem As TLISTNODE##list_type Ptr) As TLISTNODE##list_type Ptr
            Declare Function GetPrev(pItem As TLISTNODE##list_type Ptr) As TLISTNODE##list_type Ptr
            Declare Function GetSize() As Long
            Declare Function GetValueIndex(iIndex As Long) As list_type
            Declare Function GetValue(pItem As TLISTNODE##list_type Ptr) As list_type
        End Type
      
        Destructor TLIST##list_type()
            DeleteAll()
        End Destructor
      
        Sub TLIST##list_type.Add(xValue As list_type)
            Dim As TLISTNODE##list_type Ptr pTemp = New TLISTNODE##list_type
            pTemp->xValue = xValue
            If pFirst = 0 Then
                pFirst = pTemp
                pLast = pTemp
            Else
                pLast->pNext = pTemp
                pTemp->pPrev = pLast
                pLast = pTemp
            EndIf
            iSize+=1
        End Sub
      
        Sub TLIST##list_type.InsertItemIndex(iIndex As Long , xValue As list_type)
            If pFirst = 0 OrElse iIndex >= iSize Then 
                This.Add(xValue)
                Exit Sub
            EndIf
            If iIndex < 0 Then
                Exit Sub
            EndIf
         
            Dim pFind As TLISTNODE##list_type Ptr = pFirst
            For i As Long = 0 To iIndex
                If i = iIndex Then
                    Exit For
                EndIf
                If pFind->pNext Then
                    pFind = pFind->pNext   
                EndIf
            Next
            InsertItem(pFind , xValue)
        End Sub
      
        Sub TLIST##list_type.InsertItem(pItem As TLISTNODE##list_type Ptr, xValue As list_type)
            If pFirst = 0 OrElse pItem = 0 Then
                This.Add(xValue)
                Exit Sub
            EndIf
         
            Dim As TLISTNODE##list_type Ptr pTemp = New TLISTNODE##list_type
            pTemp->xValue = xValue
            If pItem = pFirst Then
                pTemp->pNext = pFirst
                pFirst = pTemp
            Else
                pTemp->pNext = pItem
                pTemp->pPrev = pItem->pPrev
                pItem->pPrev->pNext = pTemp
                pItem->pPrev = pTemp
            EndIf
            iSize+=1   
        End Sub
      
        Sub TLIST##list_type.DeleteItemIndex(iIndex As Long)
            If pFirst = 0 OrElse iIndex >= iSize OrElse iIndex < 0 OrElse iSize = 0 Then
                Exit Sub
            EndIf
         
            Dim pFind As TLISTNODE##list_type Ptr = pFirst
            For i As Long = 0 To iIndex
                If i = iIndex Then
                    Exit For
                EndIf
            
                If pFind->pNext Then
                    pFind = pFind->pNext   
                EndIf
            Next
            DeleteItem(pFind)
        End Sub
      
        Sub TLIST##list_type.DeleteItem(pItem As TLISTNODE##list_type Ptr)
            If pItem = 0 OrElse iSize = 0 Then
                Exit Sub
            EndIf
         
            If pItem = pFirst Then
                pFirst = pFirst->pNext
                If pFirst Then
                    pFirst->pPrev = 0
                EndIf
            
                If pItem = pLast Then
                    pLast = pFirst
                EndIf
            ElseIf pItem = pLast Then
                pLast = pLast->pPrev
                pLast->pNext = 0
            Else
                pItem->pPrev->pNext = pItem->pNext
                pItem->pNext->pPrev = pItem->pPrev 
            EndIf
                Delete pItem
                iSize -=1
                If iSize = 0 Then
                    pFirst = 0
                    pLast = 0
                EndIf
        End Sub
      
        Sub TLIST##list_type.DeleteAll()
            Dim As TLISTNODE##list_type Ptr pDel , pTemp = pFirst
            While pTemp
                pDel = pTemp
                pTemp = pTemp->pNext
                Delete pDel
            Wend
            iSize = 0
            pFirst = 0
            pLast = 0
        End Sub
      
        Sub TLIST##list_type.SetValueIndex(iIndex As Long , xValue As list_type)
            If pFirst = 0 OrElse iIndex >= iSize OrElse iIndex < 0 OrElse iSize = 0 Then
                Exit Sub
            EndIf
         
            Dim pFind As TLISTNODE##list_type Ptr = pFirst
            For i As Long = 0 To iIndex
                If i = iIndex Then
                    Exit For
                EndIf
            
                If pFind->pNext Then
                    pFind = pFind->pNext   
                EndIf
            Next
            pFind->xValue = xValue
        End Sub
      
        Sub TLIST##list_type.SetValue(pItem As TLISTNODE##list_type Ptr , xValue As list_type)
            If pItem = 0 OrElse pFirst = 0 Then
                Exit Sub
            EndIf
            pItem->xValue = xValue
        End Sub
      
        Sub TLIST##list_type.MoveItemIndex(iIndexFrom As Long , iIndexTo As Long)
            If pFirst = 0 OrElse iIndexFrom >= iSize OrElse iIndexFrom < 0 _
            OrElse iIndexTo >=iSize OrElse iIndexTo < 0 OrElse iSize < 2 _
            OrElse iIndexFrom = iIndexTo Then
                Exit Sub
            EndIf
         
            Dim pFindFrom As TLISTNODE##list_type Ptr = pFirst
            Dim pFindTo As TLISTNODE##list_type Ptr = pFirst         
            Dim pResultFrom As TLISTNODE##list_type Ptr         
            Dim pResultTo As TLISTNODE##list_type Ptr         
            For i As Long = 0 To iSize - 1            
                If i = iIndexFrom Then               
                    pResultFrom = pFindFrom               
                    If pResultTo Then                  
                        Exit For                 
                    EndIf               
                EndIf
        
                If pFindFrom->pNext Then               
                    pFindFrom = pFindFrom->pNext                  
                EndIf
        
                If i = iIndexTo Then               
                    pResultTo = pFindTo               
                    If pResultFrom Then                  
                        Exit For                  
                    EndIf              
                EndIf
                
                If pFindTo->pNext Then               
                    pFindTo = pFindTo->pNext               
                EndIf            
            Next        
            MoveItem(pResultFrom , pResultTo)         
        End Sub
      
        Sub TLIST##list_type.MoveItem(pItemFrom As TLISTNODE##list_type Ptr , pItemTo As TLISTNODE##list_type Ptr)         
            If pItemFrom = 0 OrElse pItemTo = 0 OrElse pItemFrom = pItemTo OrElse pFirst = 0 OrElse iSize < 2 Then            
                Exit Sub           
            EndIf
         
            If pItemFrom = pFirst AndAlso pItemTo = pLast Then            
                pFirst = pFirst->pNext            
                pFirst->pPrev = 0            
                pItemFrom->pPrev = pLast            
                pLast->pNext = pItemFrom            
                pItemFrom->pNext = 0            
                pLast = pItemFrom            
            ElseIf pItemFrom = pLast AndAlso pItemTo = pFirst Then            
                pLast = pLast->pPrev            
                pLast->pNext = 0            
                pItemFrom->pNext = pFirst            
                pFirst->pPrev = pItemFrom            
                pItemFrom->pPrev = 0            
                pFirst = pItemFrom            
            ElseIf pItemFrom = pLast Then            
                pLast = pLast->pPrev           
                pItemFrom->pPrev = pItemTo->pPrev            
                pItemTo->pPrev->pNext = pItemFrom            
                pItemFrom->pNext = pItemTo            
                pItemTo->pPrev = pItemFrom            
                pLast->pNext = 0            
            ElseIf pItemFrom = pFirst Then            
                pFirst = pFirst->pNext            
                pItemFrom->pNext = pItemTo->pNext            
                pItemTo->pNext->pPrev = pItemFrom            
                pItemFrom->pPrev = pItemTo            
                pItemTo->pNext = pItemFrom            
                pFirst->pPrev = 0            
            ElseIf pItemTo = pFirst Then            
                pItemFrom->pNext->pPrev = pItemFrom->pPrev            
                pItemFrom->pPrev->pNext = pItemFrom->pNext            
                pItemFrom->pNext = pItemTo            
                pItemTo->pPrev = pItemFrom            
                pItemFrom->pPrev = 0            
                pFirst = pItemFrom            
            ElseIf pItemTo = pLast Then            
                pItemFrom->pNext->pPrev = pItemFrom->pPrev            
                pItemFrom->pPrev->pNext = pItemFrom->pNext            
                pItemFrom->pPrev = pItemTo            
                pItemTo->pNext = pItemFrom            
                pItemFrom->pNext = 0            
                pLast = pItemFrom            
            Else            
                pItemFrom->pPrev->pNext = pItemFrom->pNext            
                pItemFrom->pNext->pPrev = pItemFrom->pPrev            
                If pItemFrom<pItemTo Then               
                    pItemFrom->pNext = pItemTo->pNext               
                    pItemTo->pNext->pPrev = pItemFrom               
                    pItemTo->pNext = pItemFrom               
                    pItemFrom->pPrev = pItemTo               
                Else               
                    pItemTo->pPrev->pNext = pItemFrom               
                    pItemFrom->pPrev = pItemTo->pPrev               
                    pItemFrom->pNext = pItemTo               
                    pItemTo->pPrev = pItemFrom               
                EndIf            
            EndIf         
        End Sub
      
        Function TLIST##list_type.GetFirst() As TLISTNODE##list_type Ptr         
            Return pFirst         
        End Function
      
        Function TLIST##list_type.GetLast() As TLISTNODE##list_type Ptr        
            Return pLast         
        End Function
      
        Function TLIST##list_type.GetNext(pItem As TLISTNODE##list_type Ptr) As TLISTNODE##list_type Ptr         
            Return pItem->pNext         
        End Function
      
        Function TLIST##list_type.GetPrev(pItem As TLISTNODE##list_type Ptr) As TLISTNODE##list_type Ptr         
            Return pItem->pPrev         
        End Function
      
        Function TLIST##list_type.GetSize() As Long        
            Return iSize        
        End Function
      
        Function TLIST##list_type.GetValueIndex(iIndex As Long) As list_type         
            If iIndex >= 0 AndAlso iIndex < iSize AndAlso pFirst <> 0 Then                     
	            Dim As TLISTNODE##list_type Ptr pTemp = pFirst         
	            For i As Long = 0 To iIndex           
	                If iIndex = i Then              
	                    Exit For               
	                EndIf
	            
	                If pTemp->pNext Then              
	                    pTemp = pTemp->pNext               
	                EndIf            
	            Next         
	            Return pTemp->xValue   
            End If       
        End Function
      
        Function TLIST##list_type.GetValue(pItem As TLISTNODE##list_type Ptr) As list_type         
            Return pItem->xValue 
        End Function
    #endif
#endmacro
